package com.linkoog.devtools.code_generator.wizard.model;

import com.intellij.ui.BooleanTableCellEditor;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.JBColor;
import com.intellij.ui.dualView.TreeTableView;
import com.intellij.ui.treeStructure.treetable.*;
import com.intellij.util.ui.ColumnInfo;
import com.linkoog.devtools.code_generator.common.JavaType;
import com.linkoog.devtools.intellij.ui.table.cell_editor.ComboEnumTableCellEditor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;

public class ModelJsonTreeTable extends TreeTableView {

    private JsonTreeTableRenderer treeRenderer = new JsonTreeTableRenderer();

    public ModelJsonTreeTable() {
        super(new ModelJsonTreeTableModel());

        JTableHeader tableHeader = getTableHeader();
        tableHeader.setReorderingAllowed(false); //禁止拖动表头

        DefaultTableCellRenderer headerRenderer = new DefaultTableCellRenderer();
        headerRenderer.setHorizontalAlignment(SwingConstants.CENTER);
        tableHeader.setDefaultRenderer(headerRenderer);
        //setRowSelectionAllowed(false);
        //setBorder(Borders.empty(1));

        setRowMargin(1);
        setRowHeight(20);
        //setAutoResizeMode(AUTO_RESIZE_LAST_COLUMN);
        setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);

        this.setRootVisible(true);
        this.setVisible(true);
        this.setSelectionForeground(JBColor.black);
        this.setSelectionBackground(JBColor.white);
        this.setTreeCellRenderer(treeRenderer);
        this.setRowSelectionAllowed(false);
        //this.setFocusable(true);
        this.setCellSelectionEnabled(true);

        TreeTableTree tableTree = this.getTree();
        ModelJsonTreeTableModel model = (ModelJsonTreeTableModel)tableTree.getModel();

        final ColumnInfo[] columns = model.getColumns();
        JavaTypeColumnInfo javaTypeColumnInfo = (JavaTypeColumnInfo) columns[2];
        javaTypeColumnInfo.setTable(this);

        OprateColumnInfo oprateColumnInfo = (OprateColumnInfo)columns[4];
        oprateColumnInfo.setTable(this);

        addMouseListener(new MouseAdapter() {
            private final ModelJsonTreeTable jsonTreeTable = ModelJsonTreeTable.this;

            @Override
            public void mousePressed(MouseEvent e) {
                handleMouse(e);
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                handleMouse(e);
            }

            private void handleMouse(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    //JPopupMenu menu = createPopup();
                    //menu.show(e.getComponent(), e.getX(), e.getY());
                }
            }

            @Override
            public void mouseClicked(MouseEvent e) {
                int row = rowAtPoint(e.getPoint());// 得到table的行号
                int col = columnAtPoint(e.getPoint());// 得到table的列号

                if (col == 0){
                }else if (row > -1 && col == jsonTreeTable.getColumnCount() - 1){
                    Object cellValue = (getModel()).getValueAt(row, col);
                    //System.out.println("单击鼠标 "+( row +1 )+"行"+ col +"列" + cellValue);
                    //System.out.println("getRowCount" + getRowCount());
                    //System.out.println("mouseClicked");
                    startEdit(row, col);
                }
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                int row = rowAtPoint(e.getPoint());// 得到table的行号
                int col = columnAtPoint(e.getPoint());// 得到table的列号
                if (row > -1 && col == jsonTreeTable.getColumnCount() - 1){
                    //Object cellValue = (getModel()).getValueAt(row, col);
                    //System.out.println("单击鼠标 "+( row +1 )+"行"+ col +"列" + cellValue);
                    //System.out.println("mouseEntered");
                    startEdit(row, col);
                }
            }

            private void startEdit(int row, int col){
                jsonTreeTable.editCellAt(row, col);
                OprateRowCellEditer oprateRowCellEditer = (OprateRowCellEditer)jsonTreeTable.getCellEditor(row, col);
                Component editerComponent = oprateRowCellEditer.getEditerComponent();
                if (editerComponent != null){
                    editerComponent.requestFocus();
                    //IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(editerComponent, true));
                }
            }


        });

        addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(FocusEvent e) {

            }

            @Override
            public void focusLost(FocusEvent e) {
            }
        });
    }

    public ItemInfo getRoot(){
        return (ItemInfo)getTableModel().getRoot();
    }

    public void expandAll() {
        TreeNode root = (TreeNode) getTree().getModel().getRoot();
        expandAll(new TreePath(root));
    }

    public void expandAll(TreePath parent) {
        TreeNode node = (TreeNode) parent.getLastPathComponent();
        if (node.getChildCount() >= 0) {
            for (Enumeration e = node.children(); e.hasMoreElements(); ) {
                TreeNode n = (TreeNode) e.nextElement();
                TreePath path = parent.pathByAddingChild(n);
                expandAll(path);
            }
        }
        getTree().expandPath(parent);
    }

    public static ModelJsonTreeTable.ItemInfo createRootNode(){
        ModelJsonTreeTable.ItemInfo root = new ModelJsonTreeTable.ItemInfo();
        root.setRootFlag(true);
        root.setName("root");
        root.setChecked(true);
        root.setCheckEditable(false);
        root.setType(JavaType.OBJECT);
        root.setTypeEditable(false);
        root.setRemark("");
        return root;
    }

    public void setModel(ModelJsonTreeTableModel treeTableModel) {
        JavaTypeColumnInfo javaTypeColumnInfo = (JavaTypeColumnInfo)treeTableModel.getColumns()[2];
        javaTypeColumnInfo.setTable(this);
        super.setModel(treeTableModel);
        this.setTreeCellRenderer(treeRenderer);
    }

    public void setModel(ItemInfo root){
        setModel(new ModelJsonTreeTableModel(root));
    }

    public ModelJsonTreeTableModel getTreeModel(){
        return (ModelJsonTreeTableModel)getModel();
    }




    public static ColumnInfo[] getTreeColumnInfos(){
        ColumnInfo[] columns = new ColumnInfo[]{
                //树形
                createNameColumnInfo(),
                createCheckedColumnInfo(),
                createJavaTypeColumnInfo(),
                createRemarkColumnInfo(),
                createOprateColumnInfo(),
        };
        return columns;
    }



    private static TreeColumnInfo createNameColumnInfo(){
        return new TreeColumnInfo("名称") {
            @Override
            public int getWidth(JTable table) {
                return 156;
            }

            @Override
            public boolean isCellEditable(Object o) {
                ModelJsonTreeTable.ItemInfo itemInfo = (ModelJsonTreeTable.ItemInfo)o;
                return itemInfo.isNameEditable();
            }

            @Override
            public void setValue(Object o, Object value) {
                ModelJsonTreeTable.ItemInfo itemInfo = (ModelJsonTreeTable.ItemInfo)o;
                itemInfo.setName((String) value);
            }

            @Override
            public TableCellEditor getEditor(Object o) {
                ModelJsonTreeTable.ItemInfo itemInfo = (ModelJsonTreeTable.ItemInfo)o;
                return new ModelTreeTableCellEditor();
            }
        };
    }

    private static ColumnInfo createCheckedColumnInfo(){
        return new ColumnInfo<ModelJsonTreeTable.ItemInfo, Boolean>("启用") {
            @Override
            public int getWidth(JTable table) {
                return 45;
            }

            @Override
            public Class getColumnClass() {
                return Boolean.class;
            }

            @Override
            public Boolean valueOf(ModelJsonTreeTable.ItemInfo itemInfo) {
                return itemInfo.isChecked();
            }

            @Override
            public boolean isCellEditable(ModelJsonTreeTable.ItemInfo itemInfo) {
                return itemInfo.isCheckEditable();
            }

            @Override
            public void setValue(ModelJsonTreeTable.ItemInfo itemInfo, final Boolean value) {
                itemInfo.setChecked(value);
            }

            @Override
            public TableCellEditor getEditor(ModelJsonTreeTable.ItemInfo itemInfo) {
                return new BooleanTableCellEditor();
            }
        };
    }

    private static JavaTypeColumnInfo createJavaTypeColumnInfo(){
        return new JavaTypeColumnInfo("Java类型");
    }

    public static class JavaTypeColumnInfo extends ColumnInfo<ModelJsonTreeTable.ItemInfo, String>{

        private ModelJsonTreeTable table;

        public JavaTypeColumnInfo(String name) {
            super(name);
        }

        public void setTable(ModelJsonTreeTable table) {
            this.table = table;
        }

        @Override
        public int getWidth(JTable table) {
            return 120;
        }



        @Override
        public Class getColumnClass() {
            return String.class;
        }

        @Override
        public String valueOf(ModelJsonTreeTable.ItemInfo itemInfo) {
            return itemInfo.getType().getName();
        }

        @Override
        public boolean isCellEditable(ModelJsonTreeTable.ItemInfo itemInfo) {
            return itemInfo.isTypeEditable();
        }

        @Override
        public void setValue(ModelJsonTreeTable.ItemInfo itemInfo, final String value) {
            JavaType oldType = itemInfo.getType();
            JavaType newType = JavaType.valueOfName(value);
            if (table != null){
                TreeTableTree tableTree = table.getTree();
                ModelJsonTreeTableModel model = (ModelJsonTreeTableModel)tableTree.getModel();
                if (oldType == JavaType.OBJECT || oldType == JavaType.LIST){
                    while (itemInfo.getChildCount() > 0){
                        ModelJsonTreeTable.ItemInfo treeNode = (ModelJsonTreeTable.ItemInfo)itemInfo.getChildAt(0);
                        model.removeNodeFromParent(treeNode);
                    }
                }

                if (newType == JavaType.LIST){
                    ModelJsonTreeTable.ItemInfo item = new ModelJsonTreeTable.ItemInfo();
                    item.setName("Items");
                    item.setNameEditable(false);
                    item.setChecked(true);
                    item.setCheckEditable(false);
                    item.setType(JavaType.STRING);
                    item.setRemark("");

                    model.insertNodeInto(item, itemInfo, itemInfo.getChildCount());
                    table.expandAll();
                }
            }
            itemInfo.setType(newType);
        }

        @Override
        public TableCellEditor getEditor(ModelJsonTreeTable.ItemInfo itemInfo) {
            ComboEnumTableCellEditor jComboEnumTableCellEditor = new ComboEnumTableCellEditor(JavaType.class, false);
            return jComboEnumTableCellEditor;
        }

        @Override
        public TableCellRenderer getRenderer(ModelJsonTreeTable.ItemInfo item) {
            DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
            renderer.setHorizontalAlignment(SwingConstants.CENTER);
            return renderer;
        }
    }


    private static ColumnInfo createRemarkColumnInfo(){
        return new ColumnInfo<ModelJsonTreeTable.ItemInfo, String>("注释") {
            @Override
            public int getWidth(JTable table) {
                return -1;
            }
            @Nullable
            @Override
            public String valueOf(ModelJsonTreeTable.ItemInfo itemInfo) {
                return itemInfo.getRemark();
            }

            @Override
            public boolean isCellEditable(ModelJsonTreeTable.ItemInfo itemInfo) {
                return true;
            }

            @Override
            public void setValue(ModelJsonTreeTable.ItemInfo itemInfo, String value) {
                itemInfo.setRemark(value);
            }
        };
    }

    private static OprateColumnInfo createOprateColumnInfo(){
        return new OprateColumnInfo(" ");
    }

    public static class OprateColumnInfo extends ColumnInfo<ModelJsonTreeTable.ItemInfo, ModelJsonTreeTable.ItemInfo>{
        private ModelJsonTreeTable table;

        public OprateColumnInfo(String name) {
            super(name);
        }

        public void setTable(ModelJsonTreeTable table) {
            this.table = table;
        }

        @Override
        public int getWidth(JTable table) {
            return 66;
        }
        @Override
        public Class getColumnClass() {
            return ModelJsonTreeTable.ItemInfo.class;
        }

        @Override
        public ModelJsonTreeTable.ItemInfo valueOf(ModelJsonTreeTable.ItemInfo itemInfo) {
            return itemInfo;
        }

        @Override
        public boolean isCellEditable(ModelJsonTreeTable.ItemInfo itemInfo) {
            return true;
        }

        @Override
        public OprateRowCellEditer getEditor(ModelJsonTreeTable.ItemInfo itemInfo) {
            return new OprateRowCellEditer(itemInfo);
        }

        @Override
        public OprateRowCellRender getRenderer(ModelJsonTreeTable.ItemInfo itemInfo) {
            //return getEditor(itemInfo);
            System.out.println("=======");
            return new OprateRowCellRender(table, itemInfo);
        }
    }


    public static class ItemInfo extends DefaultMutableTreeNode{
        private boolean rootFlag;
        private String name = "";
        private boolean nameEditable = false;

        private boolean checked = true;
        private boolean checkEditable = true;

        private JavaType type = JavaType.STRING;
        private boolean typeEditable = true;

        private String remark = "";

        public boolean isRootFlag() {
            return rootFlag;
        }

        public void setRootFlag(boolean rootFlag) {
            this.rootFlag = rootFlag;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public boolean isNameEditable() {
            return nameEditable;
        }

        public void setNameEditable(boolean nameEditable) {
            this.nameEditable = nameEditable;
        }

        public boolean isChecked() {
            return checked;
        }

        public void setChecked(boolean checked) {
            this.checked = checked;
        }

        public boolean isCheckEditable() {
            return checkEditable;
        }

        public void setCheckEditable(boolean checkEditable) {
            this.checkEditable = checkEditable;
        }

        public JavaType getType() {
            return type;
        }

        public void setType(JavaType type) {
            this.type = type;
        }

        public boolean isTypeEditable() {
            return typeEditable;
        }

        public void setTypeEditable(boolean typeEditable) {
            this.typeEditable = typeEditable;
        }

        public String getRemark() {
            return remark;
        }

        public void setRemark(String remark) {
            this.remark = remark;
        }



        @Override
        public String toString() {
            return "ItemInfo{" +
                    "rootFlag=" + rootFlag +
                    ", name='" + name + '\'' +
                    ", nameEditable=" + nameEditable +
                    ", checked=" + checked +
                    ", checkEditable=" + checkEditable +
                    ", type=" + type +
                    ", remark='" + remark + '\'' +
                    '}';
        }
    }

    private class JsonTreeTableRenderer extends ColoredTreeCellRenderer {
        @Override
        public void customizeCellRenderer(@NotNull JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
            //解决TreeTable key加上>
            ItemInfo node = (ItemInfo) value;
            //setBorder(BorderFactory.createLineBorder(JBColor.BLACK, 3));
            append(node.getName());
            setIcon(node.type.getIcon());
        }
    }

}
